/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期: 2020年1月4日
 */
package com.massyframework.beanskin.maven.plugin.util;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * {@link MapVariableReplacer},简单的字符变量替换器
 * 
 * @author Huangkaihui
 *
 */
public final class MapVariableReplacer implements StringVariableReplacer {

	protected static final String EMPTY = "";

	private Map<String, String> variableMap;
	private Pattern pattern;

	/**
	 * 构造方法
	 */
	public MapVariableReplacer() {
		this(null);
	}
	
	/**
	 * 构造方法
	 * @param variables {@link Map}
	 */
	public MapVariableReplacer(Map<String, String> variables) {
		this.variableMap = variables == null ?
				new HashMap<>() :
				new HashMap<>(variables);
	}

	@Override
	public void addVariable(String name, String value) {
		if (name != null && value != null) {
			this.variableMap.put(name, value);
			this.pattern = this.buildPattern();
		}

	}

	@Override
	public void addVariables(Map<String, String> value) {
		if (value != null && !value.isEmpty()) {
			this.variableMap.putAll(value);
			this.pattern = this.buildPattern();
		}
	}

	@Override
	public String foundAndReplace(String text) {
		if (text == null)
			return null;
		if (text.length() < 4)
			return text;

		Pattern pattern = this.pattern;
		if (pattern == null)
			return text;

		Matcher matcher = pattern.matcher(text);
		StringBuffer sb = new StringBuffer();
		while (matcher.find()) {
			matcher.appendReplacement(sb, this.variableMap.get(matcher.group(1)));
		}
		matcher.appendTail(sb);
		return sb.length() == 0 ? text : sb.toString();
	}

	@Override
	public void removeVariable(String name) {
		if (this.variableMap.remove(name) != null) {
			this.pattern = this.buildPattern();
		}
	}

	@Override
	public void removeVariables(Collection<String> names) {
		if (names == null)
			return;
		if (names.isEmpty())
			return;

		boolean removed = false;
		for (String name : names) {
			if (this.variableMap.remove(name) != null) {
				removed = true;
			}
		}

		if (removed) {
			this.pattern = this.buildPattern();
		}
	}

	@Override
	public void removeVariables(String... names) {
		if (names == null)
			return;
		if (names.length == 0)
			return;

		boolean removed = false;
		for (String name : names) {
			if (this.variableMap.remove(name) != null) {
				removed = true;
			}
		}

		if (removed) {
			this.pattern = this.buildPattern();
		}

	}

	/**
	 * 构建变量替换的模式
	 */
	protected Pattern buildPattern() {
		String patternString = "\\$\\{(" + join(this.variableMap.keySet().iterator(), "|") + ")\\}";
		return Pattern.compile(patternString);
	}

	private String join(final Iterator<?> iterator, final String separator) {

		// handle null, zero and one elements before building a buffer
		if (iterator == null) {
			return null;
		}
		if (!iterator.hasNext()) {
			return EMPTY;
		}
		final Object first = iterator.next();
		if (!iterator.hasNext()) {
			return Objects.toString(first, "");
		}

		// two or more elements
		final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
		if (first != null) {
			buf.append(first);
		}

		while (iterator.hasNext()) {
			if (separator != null) {
				buf.append(separator);
			}
			final Object obj = iterator.next();
			if (obj != null) {
				buf.append(obj);
			}
		}
		return buf.toString();
	}

}
